﻿using System;
using System.Windows.Input;
using IronCow;
using Milkify.Data;
using Milkify.Input;
using Milkify.Interfaces;

namespace Milkify.Controllers
{
    class TaskController : Controller
    {
        private IView mView;

        public TaskController(ControllerContext context, Rtm rtm, IViewContainer viewContainer, IViewFactory viewFactory)
            : base(context, rtm, viewContainer)
        {
            mView = viewFactory.Create("Task");
        }

        public override void Execute()
        {
            // Create commands.
            ICommand editTaskCommand = new DecoupledCommand(EditTask);
            ICommand editTaskParameterCommand = new DecoupledCommand<string>(EditTaskParameter);
            ICommand completeTaskCommand = new DecoupledCommand(CompleteTask);
            ICommand postponeTaskCommand = new DecoupledCommand(PostponeTask);
            ICommand deleteTaskCommand = new DecoupledCommand(DeleteTask);
            ICommand uncompleteTaskCommand = new DecoupledCommand(UncompleteTask);
            ICommand navigateToTaskListCommand = new DecoupledCommand(NavigateToTaskList);
            ICommand navigateToTagCommand = new DecoupledCommand<string>(NavigateToTag);
            ICommand navigateToTaskNoteListCommand = new DecoupledCommand(NavigateToTaskNoteList);
            ICommand navigateToTaskUrlCommand = new DecoupledCommand<string>(NavigateToTaskUrl);
            ICommand addNoteCommand = new DecoupledCommand(AddTaskNote);

            // Register input bindings.
            RegisterInputBindings(editTaskCommand, completeTaskCommand, postponeTaskCommand, addNoteCommand);

            // Assign view data.
            var task = Context.CommandParameter as Task;
            if (task == null)
                throw new InvalidOperationException("No task was given to display.");
            var viewData = new TaskViewData(task)
            {
                EditTaskCommand = editTaskCommand,
                EditTaskParameterCommand = editTaskParameterCommand,
                CompleteTaskCommand = completeTaskCommand,
                PostponeTaskCommand = postponeTaskCommand,
                DeleteTaskCommand = deleteTaskCommand,
                UncompleteTaskCommand = uncompleteTaskCommand,
                NavigateToTaskListCommand = navigateToTaskListCommand,
                NavigateToTagCommand = navigateToTagCommand,
                NavigateToTaskNoteListCommand = navigateToTaskNoteListCommand,
                NavigateToTaskUrlCommand = navigateToTaskUrlCommand
            };
            mView.ViewData = viewData;

            ViewContainer.NavigateToView(mView);
        }

        private void RegisterInputBindings(ICommand editTaskCommand, ICommand completeTaskCommand, ICommand postponeTaskCommand, ICommand addNoteCommand)
        {
            Milkify.Diagnostics.MilkifyTraceSources.UISource.TraceEvent(System.Diagnostics.TraceEventType.Start, 0, "Registering task window input bindings.");

            // Complete task
            InputBinding inputBinding = new InputBinding(completeTaskCommand, KeyboardShortcutHelper.GetKeyGesture("CompleteTaskShortcut"));
            mView.InputBindings.Add(inputBinding);

            // Postpone task
            inputBinding = new InputBinding(postponeTaskCommand, KeyboardShortcutHelper.GetKeyGesture("PostponeTaskShortcut"));
            mView.InputBindings.Add(inputBinding);

            // Change name
            inputBinding = new InputBinding(CreateEditTaskParameterCommand("Name"), KeyboardShortcutHelper.GetKeyGesture("ChangeTaskNameShortcut"));
            mView.InputBindings.Add(inputBinding);

            // Change due date
            inputBinding = new InputBinding(CreateEditTaskParameterCommand("DueDate"), KeyboardShortcutHelper.GetKeyGesture("ChangeTaskDueDateShortcut"));
            mView.InputBindings.Add(inputBinding);

            // Change repeat
            inputBinding = new InputBinding(CreateEditTaskParameterCommand("Repeat"), KeyboardShortcutHelper.GetKeyGesture("ChangeTaskRepeatShortcut"));
            mView.InputBindings.Add(inputBinding);

            // Change time estimate
            inputBinding = new InputBinding(CreateEditTaskParameterCommand("Estimate"), KeyboardShortcutHelper.GetKeyGesture("ChangeTaskEstimateShortcut"));
            mView.InputBindings.Add(inputBinding);

            // Change tags
            inputBinding = new InputBinding(CreateEditTaskParameterCommand("Tags"), KeyboardShortcutHelper.GetKeyGesture("ChangeTaskTagsShortcut"));
            mView.InputBindings.Add(inputBinding);

            // Change URL
            inputBinding = new InputBinding(CreateEditTaskParameterCommand("Url"), KeyboardShortcutHelper.GetKeyGesture("ChangeTaskUrlShortcut"));
            mView.InputBindings.Add(inputBinding);

            // Change location
            inputBinding = new InputBinding(CreateEditTaskParameterCommand("Location"), KeyboardShortcutHelper.GetKeyGesture("ChangeTaskLocationShortcut"));
            mView.InputBindings.Add(inputBinding);

            // Add note
            inputBinding = new InputBinding(addNoteCommand, KeyboardShortcutHelper.GetKeyGesture("AddTaskNoteShortcut"));
            mView.InputBindings.Add(inputBinding);

            Milkify.Diagnostics.MilkifyTraceSources.UISource.TraceEvent(System.Diagnostics.TraceEventType.Stop, 0);
        }

        private ICommand CreateEditTaskParameterCommand(string parameterName)
        {
            return new DecoupledCommand(() =>
                {
                    EditTaskParameter(parameterName);
                });
        }

        private void EditTask()
        {
            var viewData = (TaskViewData)mView.ViewData;
            Redirect("TaskEdit", "EditTasks", new Task[] { viewData.Task });
        }

        private void EditTaskParameter(string parameterName)
        {
            var viewData = (TaskViewData)mView.ViewData;
            Redirect("TaskEdit", "EditTasks" + parameterName, new Task[] { viewData.Task });
        }

        private void CompleteTask()
        {
            var viewData = (TaskViewData)mView.ViewData;
            viewData.Task.Complete();
            GoBackAndRefreshTaskListView(viewData.Task.Parent);
        }

        private void PostponeTask()
        {
            var viewData = (TaskViewData)mView.ViewData;
            viewData.Task.Postpone();
            GoBackAndRefreshTaskListView(viewData.Task.Parent);
        }

        private void DeleteTask()
        {
            var viewData = (TaskViewData)mView.ViewData;
            viewData.Task.Delete();
            GoBackAndRefreshTaskListView(viewData.Task.Parent);
        }

        private void UncompleteTask()
        {
            var viewData = (TaskViewData)mView.ViewData;
            viewData.Task.Uncomplete();
            GoBackAndRefreshTaskListView(viewData.Task.Parent);
        }

        private void AddTaskNote()
        {
            var viewData = (TaskViewData)mView.ViewData;
            Redirect("TaskNoteEdit", "AddTaskNote", viewData.Task);
        }

        private void NavigateToTaskList()
        {
            var viewData = (TaskViewData)mView.ViewData;
            Redirect("TaskList", "NavigateToTaskList", new TaskListViewData(viewData.Task.Parent));
        }

        private void NavigateToTag(string tag)
        {
            Redirect("TaskList", "NavigateToTag", tag);
        }

        private void NavigateToTaskNoteList()
        {
            var viewData = (TaskViewData)mView.ViewData;
            Redirect("TaskNoteList", "NavigateToTaskNoteList", viewData.Task);
        }

        private void NavigateToTaskUrl(string url)
        {
            System.Diagnostics.Process.Start(url);
        }

        private void GoBackAndRefreshTaskListView(TaskList taskList)
        {
            ViewContainer.InvalidateRefreshableViews();
            ViewContainer.NavigateBack();
        }
    }
}
